use std::collections::HashMap;


/**
                   第八章  通用集合类型----String
        使用字符串存储UTF-8编码的文本

*/
fn main() {
    println!("Hello, world!");

    //使用字符串存储UTF-8编码的文本
    //字符串是什么:Rust在语言核心部分只有一种字符串类型，那就是字符串切片str，它通常以借用的形式（&str）出现。
    //当Rust开发者们提到“字符串”时，他们通常指的是String与字符串切片&str这两种类型，而不仅仅只是其中的一种。
    // 虽然本节会着重介绍String，但是这两种类型都广泛地被应用于Rust标准库中，并且都采用了UTF-8编码。
    //Rust的标准库中同时包含了其他一系列的字符串类型，比如OsString、OsStr、CString及CStr。

    //1.创建一个新的字符串
    let mut _s =String::new();
    //可以对那些实现display trait的类型使用to_string方法  初始化数据;
    let data="hello world";
    let _data_str =data.to_string();
    //上面两行等同于
    let _data_str_bak ="hello world".to_string();
    //也可以使用String::from()来基于字符串生成string     String::from和to_string实际上完成了相同的工作，
    let _data_str_string =String::from("hello world");

    //2.更新字符串
    let mut str_data_up=String::from("test_update");
    str_data_up.push_str("_OK");  //这样str_data_up等于test_update_OK
    //使用push_str方法向String中添加字符串切片
    let str_ok="__OK_state";
    str_data_up.push_str(str_ok);
    println!("str_data_up is {}",str_data_up);
    // 3.使用push方法将一个字符添加到String中
    let mut str_push=String::from("lo");
    str_push.push('l');    //str_push等于  lol
    //3.2使用+运算符或format! 宏来拼接字符串
    let str1=String::from("hello,");
    let str2=String::from("world");
    let str3=str1+&str2;  // <-- 这里str1已经被移动且不能再被使用了    //我们在加法操作中仅对str2采用了引用，而str1在加法操作之后则不再有效
    println!("str3 is  {}",str3);
    //3.3使用+运算符拼接多个字符串，
    let str4=String::from("ta");
    let str5=String::from("-ta");
    let str6=String::from("-ta");
    let str7=str4+&str5+&str6;
    println!("str7 is  {}",str7);
    //上面多个字符串可以使用format! 宏来生成
    //format!  宏 的代码要更加易读，并且不会夺取任何参数的所有权。
    let str4=String::from("ta");
    let str5=String::from("ta");
    let str6=String::from("ta");
    let str7=format!("{}--{}--{}",str4,str5,str6);
    println!("str7 is  {}",str7);
    //4.字符串索引   Rust中的字符串并不支持索引
    let _stringier =String::from("hello");
    //let _strzero=_stringIndex[0];   //<-- 这行会报错  error[E0277]: the type `String` cannot be indexed by `{integer}`
    //String实际上是一个基于Vec<u8>的封装类型
    let index=String::from("Здравствуйте").len();   //<-- index 等于24   因为这个字符串中的每个Unicode标量值都需要占据2字节
    println!("{}",index);
    //字符串切片
    let hello="Здравствуйте";
    let hello_str=&hello[0..4];
    println!("hello_str is {}",hello_str);
    //遍历字符串的方法
    //  chars()方法返回类型为char的值  12个    З    д    р    а    в    с    т    в    у    й    т    е
    for  c in hello.chars()  {
        print!("{}    ",c);
    }
    //bytes()返回类型为原始字节        24个  208   151   208   180   209   128   208   176   208   178   209   129   209   130   208   178   209   131   208   185   209   130   208   181
    for  c in hello.bytes()  {
        print!("{}   ",c);
    }

    //字符串的确没那么简单
    // 总而言之，字符串确实是挺复杂的。
    // 不同的编程语言会做出不同的设计抉择，来确定将何种程度的复杂性展现给程序员。
    // Rust选择了将正确的String数据处理方法作为所有Rust程序的默认行为，这也就意味着程序员需要提前理解UTF-8数据的处理流程。
    // 与某些编程语言相比，这一设计暴露了字符串中更多的复杂性，但它也避免了我们在开发周期临近结束时再去处理那些涉及非ASCII字符的错误。

    /**
                              第八章 通用集合类型         在哈希映射中存储键值对
           HashMap<K, V>，它存储了从K类型键到V类型值之间的映射关系。
           哈希映射在内部实现中使用了哈希函数，这同时决定了它在内存中存储键值对的方式。
    */

    //1.创建一个新的哈希映射
    let mut scores=HashMap::new();
    scores.insert(String::from("blue"),10);
    scores.insert(String::from("yellow"),20);

    //在一个由键值对组成的元组动态数组上使用collect方法。
    let teams=vec![String::from("balck"),String::from("pink")];
    let number=vec![12,14];
    //这里的类型标记HashMap<_, _>不能被省略，因为collect可以作用于许多不同的数据结构，如果不指明类型的话，Rust就无法知道我们具体想要的类型。
    let collect:HashMap<_,_>=teams.iter().zip(number.iter()).collect();
    //2.哈希映射与所有权
    let find_name=String::from("golden");
    let find_value=String::from("green");
    let mut map=HashMap::new();
    map.insert(find_name,find_value);    //在调用insert方法后，field_name和field_value变量被移动到哈希映射中，我们再也没有办法使用这两个变量了。
    //3.访问哈希映射中的值
    let mut scores=HashMap::new();
    scores.insert(String::from("blue"),10);
    scores.insert(String::from("yellow"),20);
    let name=String::from("blue");
    let name_value=scores.get(&name);
    println!("   ");
    println!("{}",name);
    for (k,v) in scores {
        println!("{}:{}",k,v);
    }
    //更新哈希映射
    let mut scores=HashMap::new();
    scores.insert(String::from("blue"),70);
    scores.insert(String::from("yellow"),80);
    // scores.insert(String::from("blue"),30);
    //需要检测一个键是否存在对应值，如果不存在，则为它插入一个值。  通过使用entry方法在键不存在对应值时插入数据
    scores.entry(String::from("green")).or_insert(90);
    println!("{:?}",scores);
    for (k,v) in scores {
        println!("{}:{}",k,v);
    }

    //基于旧值来更新值
    let text="hello world wonderful world";
    let mut map=HashMap::new();
    for word in text.split_whitespace() {
        let count=map.entry(word).or_insert(0); //or_insert实际上为我们传入的键返回了一个指向关联值的可变引用（&mut V）。
        *count+=1;  //这个可变引用进而被存储到变量count上，为了对这个值进行赋值操作，我们必须首先使用星号（*）来对count进行解引用
    }
    println!("{:?}",map);  //{"wonderful": 1, "world": 2, "hello": 1}
}
/**
哈希函数:cd
为了提供抵御拒绝服务攻击（DoS，Denial of Service）的能力，HashMap默认使用了一个在密码学上安全的哈希函数。
这确实不是最快的哈希算法，不过为了更高的安全性付出一些性能代价通常是值得的。假如你在对代码进行性能分析的过程中，
发现默认哈希函数成为了你的性能热点并导致性能受损，你也可以通过指定不同的哈希计算工具来使用其他函数。
这里的哈希计算工具特指实现了BuildHashertrait的类型。

                                       总结
       动态数组、字符串及哈希映射为我们提供了很多用于存储、访问或修改数据的功能，你可以非常方便地将它们应用到自己的程序中。
*/
